這題會需要一些先被知識,再來寫會比較好(關於並查集如果有空再分享,最進有點懶XD)
nums
裡的數字,如果有公因數(>1)就串起來,如果最後可以形成一連串,且沒有烙單的數字就回傳true
否則false
所以我們要做的就是,看看數字間有沒有關聯,並將其串成一串
如果這麼簡單就好了 (\~ ̄▽ ̄)\~
舉個例子,4與6可以串聯,因為
這時再加入數字 9
父 6
/ \
4 9
由這個,可以讓我們想到,他們會串聯是因為因數相同,所以只要
當下一個數字進入時,重復以上動作:(6)
再重複1次(9)
現在,圖應該是這樣
父 4 6
| |
6 9
進行merge
合併相同指向(應該在找到父節點時就要做,但為了方便講解放在這裡)
*依據rank(規模)*小的合併大的
最後,執行一次跑圖(串聯)
1. 4(指向自己)
2. 6(指向4)
3. 9(指向6)
4 <-- 6 <--9
這一題我覺得算是中規中矩,有數論也有dsu,當然也有看到有人單純用數論解(狠人),如果你有興趣聽我廢話解題的話可以加入我們的dc討論,感謝你的閱讀
#define 原神啟動 on
class Solution {
// DSU
int Find_(vector<int>&f,int x){
if(f[x] != x){
f[x] = Find_(f,f[x]);
}
return f[x];
}
// merge (compress array pointer)
void merge(vector<int>&f,vector<int>&size,int x,int y){
x = Find_(f,x);
y = Find_(f,y);
// if both have same root
if(x == y)return;
// let x rank > y rank
if(size[x]<size[y]){
swap(x,y);
}
// 合併
f[y] = x;
// for anwer
size[x]+=size[y];
}
public:
bool canTraverseAllPairs(vector<int>& nums) {
const int n = nums.size();
if(n == 1) return true;
// create a dsu board
vector<int> f(n),size(n);
for(int i=0;i<n;i++){
//root is thierself
f[i] = i;
//all size = 1
size[i] = 1;
}
// store the point is root
map<int,int> have;
//find common root
for(int i=0;i<n;i++){
int num = nums[i];
if(num==1)return false;
for(int d = 2;d * d <= num;d++){
if(num % d == 0){
if(have.count(d)) merge(f,size,i,have[d]);
else have[d] = i;
while(num % d == 0) num/= d;
}
}
if(num > 1){
if(have.count(num)) merge(f,size,i,have[num]);
else have[num] = i;
}
}
return size[Find_(f,1)] == n;
}
};